package cn.edu.swufe.surverpark.struts2.service.impl;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cn.edu.swufe.surverpark.model.Answer;
import cn.edu.swufe.surverpark.model.Page;
import cn.edu.swufe.surverpark.model.Question;
import cn.edu.swufe.surverpark.model.Survey;
import cn.edu.swufe.surverpark.model.User;
import cn.edu.swufe.surverpark.struts2.dao.BaseDao;
import cn.edu.swufe.surverpark.struts2.service.SurveyService;
import cn.edu.swufe.surverpark.util.DataUtil;

/**
 * @author 陈龙 E-mail:529914446@qq.com
 * @version创建时间:2015年4月29日下午11:48:07 类说明
 */
@Service("surveyService")
public class SurveyServiceImpl implements SurveyService {

	@Resource(name = "surveyDao")
	private BaseDao<Survey> surveyDao;

	@Resource(name = "pageDao")
	private BaseDao<Page> pageDao;

	@Resource(name = "questionDao")
	private BaseDao<Question> questionDao;

	@Resource(name = "answerDao")
	private BaseDao<Answer> answerDao;

	public List<Survey> findMySurveys(User user) {
		String hql = "FROM Survey s WHERE s.user.id = ?";
		return surveyDao.findEntityByHQL(hql, user.getId());
	}

	@Override
	public Survey newSurvey(User user) {
		// TODO Auto-generated method stub
		Survey s = new Survey();
		Page p = new Page();

		s.setUser(user);
		p.setSurvey(s);
		s.getPages().add(p);
		surveyDao.saveEntity(s);
		pageDao.saveEntity(p);
		return s;
	}

	@Override
	public Survey getSurvey(Integer sid) {

		return surveyDao.getEntity(sid);
	}

	@Override
	public Survey getSurveyWithChildren(Integer sid) {
		Survey s = this.getSurvey(sid);
		for (Page p : s.getPages()) {
			p.getQuestions().size();
		}
		return s;
	}

	@Override
	public void updateSurvey(Survey model) {

		surveyDao.updateEntity(model);
	}

	@Override
	public void saveOrUpdatePage(Page model) {
		pageDao.saveOrUpdateEntity(model);
	}

	@Override
	public Page getPage(Integer pid) {
		return pageDao.getEntity(pid);
	}

	@Override
	public void saveOrUpdateQuestion(Question model) {
		System.out.println(model);
		questionDao.saveOrUpdateEntity(model);
	}

	@Override
	public void deleteQuestion(Integer qid) {
		String hql = "DELETE FROM Answer a WHERE a.questionId = ?";
		answerDao.batchEntityByHQL(hql, qid);

		hql = "DELETE FROM Question q WHERE q.id = ?";
		questionDao.batchEntityByHQL(hql, qid);
	}

	@Override
	public void deletePage(Integer pid) {
		String hql = "DELETE FROM Answer a WHERE a.questionId in (SELECT q.id from Question q WHERE q.page.id = ?)";
		answerDao.batchEntityByHQL(hql, pid);

		hql = "DELETE FROM Question q WHERE q.page.id = ?";
		questionDao.batchEntityByHQL(hql, pid);

		hql = "DELETE FROM Page p WHERE p.id = ?";
		pageDao.batchEntityByHQL(hql, pid);
	}

	@Override
	public void deleteSurvey(Integer sid) {
		// delete answer
		String hql = "DELETE Answer a WHERE a.surveyId = ?";
		answerDao.batchEntityByHQL(hql, sid);

		// delete question
		// hql = "DELETE Question q WHERE q.page.survey.id = ?";
		hql = "DELETE Question q WHERE q.page.id in (SELECT p.id FROM Page p WHERE p.survey.id = ?)";
		questionDao.batchEntityByHQL(hql, sid);

		// delete page
		hql = "DELETE Page p WHERE p.survey.id = ?";
		pageDao.batchEntityByHQL(hql, sid);

		// delete survey
		hql = "DELETE Survey s WHERE s.id = ?";
		surveyDao.batchEntityByHQL(hql, sid);
	}

	@Override
	public Question getQuestion(Integer qid) {
		// TODO Auto-generated method stub
		return questionDao.getEntity(qid);
	}

	@Override
	public void clearAnswers(Integer sid) {
		String hql = "DELETE Answer a WHERE a.surveyId = ?";
		answerDao.batchEntityByHQL(hql, sid);

	}

	@Override
	public void toggleStatus(Integer sid) {
		Survey s = this.getSurvey(sid);
		String hql = "UPDATE Survey s SET s.closed = ? WHERE s.id = ?";
		surveyDao.batchEntityByHQL(hql, !s.isClosed(), sid);
	}

	@Override
	public void updateLogoPhotoPath(Integer sid, String path) {
		String hql = "UPDATE Survey s SET s.logoPhotoPath = ? WHERE s.id = ?";
		surveyDao.batchEntityByHQL(hql, path, sid);
	}

	@Override
	public void moveOrCopyPage(Integer srcPid, Integer targPid, int pos) {
		Page srcPage = this.getPage(srcPid);
		Survey srcSurvey = srcPage.getSurvey();
		
		Page targPage = this.getPage(targPid);
		Survey targSurvey = targPage.getSurvey();
		
		if (srcSurvey.getId().equals(targSurvey.getId())) {
			// 移动
			setOrderno(srcPage, targPage, pos);
		} else {
			// 复制
			srcPage.getQuestions().size();
			Page copyPage = (Page) DataUtil.deeplyCopy(srcPage);
			copyPage.setSurvey(targSurvey);
			pageDao.saveEntity(copyPage);
			for(Question q:copyPage.getQuestions()){
				questionDao.saveEntity(q);
			}
			setOrderno(copyPage, targPage, pos);
		}
	}
	public void setOrderno(Page srcPage,Page targPage,int pos){
		if(pos == 0){//之前
			if(isFirstPage(targPage)){
				srcPage.setOrderno(targPage.getOrderno() - 0.01f);
			}else {
				Page prePage = getPrePage(targPage);
				srcPage.setOrderno((targPage.getOrderno()+prePage.getOrderno())/2);
			}
		}
		else{//之后
			if(isLastPage(targPage)){
				srcPage.setOrderno(targPage.getOrderno() + 0.01f);
			}else {
				Page nextPage = getNextPage(targPage);
				srcPage.setOrderno((targPage.getOrderno()+nextPage.getOrderno())/2);
			}
		}
	}

	private boolean isFirstPage(Page targPage){
		String hql = "SELECT COUNT(*) FROM Page p WHERE p.survey.id = ? AND p.orderno < ?";
		Long count = (Long) pageDao.uniqueResult(hql, targPage.getSurvey().getId(),targPage.getOrderno());
		return count==0;
	}
	private boolean isLastPage(Page targPage){
		String hql = "SELECT COUNT(*) FROM Page p WHERE p.survey.id = ? AND p.orderno > ?";
		Long count = (Long) pageDao.uniqueResult(hql, targPage.getSurvey().getId(),targPage.getOrderno());
		return count==0;
	}

	private Page getPrePage(Page targPage) {
		String hql = "FROM Page p WHERE p.survey.id = ? AND p.orderno < ?ORDER BY p.orderno DESC";
		List<Page> list = pageDao.findEntityByHQL(hql,targPage.getSurvey().getId(),targPage.getOrderno());
		return list.get(0);
	}
	
	private Page getNextPage(Page targPage){
		String hql = "FROM Page p WHERE p.survey.id = ? AND p.orderno > ?ORDER BY p.orderno ASC";
		List<Page> list = pageDao.findEntityByHQL(hql,targPage.getSurvey().getId(),targPage.getOrderno());
		return list.get(0);
	}
	
	@Override
	public List<Survey> getSurveyWithPages(User user) {
		String hql = "FROM Survey s WHERE s.user.id = ?";
		List<Survey> list = surveyDao.findEntityByHQL(hql, user.getId());
		for (Survey s : list)
			s.getPages().size();
		return list;
	}

	@Override
	public List<Survey> findAllAvailableSurveys() {
		String hql = "From Survey s WHERE s.closed = ?";
		return surveyDao.findEntityByHQL(hql, false);
	}

	@Override
	public Page getFirstPage(Integer sid) {
		String hql = "FROM Page p WHERE p.survey.id = ? ORDER BY p.orderno ASC";
		List<Page> list = pageDao.findEntityByHQL(hql, sid);
		Page p = list.get(0);
		p.getQuestions().size();
		p.getSurvey().getTitle();
		return p;
	}

	@Override
	public Page getPrePage(Integer currPid) {
		// TODO Auto-generated method stub
		Page p = this.getPage(currPid);
		p = this.getPrePage(p);
		p.getQuestions().size();
		return p;
	}

	@Override
	public Page getNextPage(Integer currPid) {
		Page p = this.getPage(currPid);
		p = this.getNextPage(p);
		p.getQuestions().size();
		return p;
	}

	@Override
	public void saveAnswers(List<Answer> list) {
		Date date = new Date();
		String uuid = UUID.randomUUID().toString();
		for(Answer a:list){
			a.setUuid(uuid);
			a.setAnswerTime(date);
			answerDao.saveEntity(a);
		}
	}

	@Override
	public List<Question> getQuestions(Integer sid) {
		String hql ="FROM Question q WHERE q.page.survey.id = ?";
		return questionDao.findEntityByHQL(hql, sid);
	}

	@Override
	public List<Answer> getAnswers(Integer sid) {
		String hql ="FROM Answer a where a.surveyId = ? order by a.uuid asc";
		return answerDao.findEntityByHQL(hql, sid);
	}

}
